<script lang="ts" setup>
import {onMounted, ref, watch} from 'vue'
import {useImageError} from '@/composables/useImageError'

interface Props {
  src: string
  alt?: string
  placeholder?: string
  fallback?: string
  lazy?: boolean
  maxRetries?: number
  class?: string
  fit?: 'contain' | 'cover' | 'fill' | 'none' // 新增：图片适配方式
}

const props = withDefaults(defineProps<Props>(), {
  alt: '',
  placeholder: '/placeholder.svg',
  fallback: '/placeholder-error.svg',
  lazy: true,
  maxRetries: 3,
  fit: 'contain' // 默认 contain，保持图片完整
})

const emit = defineEmits<{
  load: []
  error: [error: Event]
  retry: [count: number]
}>()

const loaded = ref(false)
const imgElement = ref<HTMLImageElement>()

// 使用图片错误处理组合式函数
const {
  currentSrc,
  isError,
  isLoading,
  handleError,
  handleLoad: onLoad,
  reset
} = useImageError({
  maxRetries: props.maxRetries,
  fallbackImage: props.fallback,
  onError: (error) => {
    emit('error', error)
  },
  onRetry: (count) => {
    emit('retry', count)
  },
  onSuccess: () => {
    loaded.value = true
    emit('load')
  }
})

// 初始化显示占位图
currentSrc.value = props.placeholder

const loadImage = () => {
  if (!props.src) return

  const img = new Image()

  img.onload = () => {
    currentSrc.value = props.src
    loaded.value = true
    isLoading.value = false
    onLoad()
    emit('load')
  }

  img.onerror = (error) => {
    handleError(error as Event, props.src)
  }

  img.src = props.src
}

// 懒加载
const setupLazyLoad = () => {
  if (!props.lazy || typeof IntersectionObserver === 'undefined') {
    loadImage()
    return
  }

  const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            loadImage()
            observer.disconnect()
          }
        })
      },
      {
        rootMargin: '50px' // 提前50px开始加载
      }
  )

  if (imgElement.value) {
    observer.observe(imgElement.value)
  }
}

onMounted(() => {
  setupLazyLoad()
})

// 监听 src 变化
watch(() => props.src, (newSrc) => {
  if (newSrc) {
    reset(newSrc)
    loaded.value = false
    loadImage()
  }
})
</script>

<template>
  <div
      :class="[props.class, { loaded, error: isError, loading: isLoading }]"
      :data-fit="fit"
      class="progressive-image"
  >
    <img
        ref="imgElement"
        :alt="alt"
        :class="{ 'fade-in': loaded }"
        :src="currentSrc"
        :style="{ objectFit: fit }"
        class="image"
    />

    <!-- 加载骨架屏 -->
    <div v-if="isLoading && !loaded" class="skeleton">
      <div class="skeleton-shimmer"></div>
    </div>

    <!-- 错误提示 -->
    <div v-if="isError" class="error-overlay">
      <div class="error-content">
        <svg class="error-icon" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
          <path
              d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"
              stroke="currentColor" stroke-width="2"/>
          <path d="M12 8V12M12 16H12.01" stroke="currentColor" stroke-linecap="round" stroke-width="2"/>
        </svg>
        <span class="error-text">加载失败</span>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
@use '@/assets/styles/variables.scss' as *;

.progressive-image {
  position: relative;
  background: $gradient-bg;
  border-radius: $radius-md;

  .image {
    width: 100%;
    height: auto;
    display: block;
    opacity: 0;
    transition: opacity 0.4s $ease-out;

    &.fade-in {
      opacity: 1;
    }
  }

  &[data-fit="cover"],
  &[data-fit="fill"] {
    overflow: hidden;
    min-height: 100px;

    .image {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  }

  &[data-fit="fill"] .image {
    object-fit: fill;
  }

  // 骨架屏
  .skeleton {
    position: absolute;
    inset: 0;
    background: linear-gradient(135deg, #faf5ff 0%, #f0f9ff 100%);
    overflow: hidden;

    .skeleton-shimmer {
      position: absolute;
      inset: 0;
      background: linear-gradient(
              90deg,
              rgba(255, 255, 255, 0) 0%,
              rgba(255, 255, 255, 0.5) 50%,
              rgba(255, 255, 255, 0) 100%
      );
      animation: shimmer 1.5s infinite;
      transform: translateX(-100%);
    }
  }

  // 错误提示
  .error-overlay {
    position: absolute;
    inset: 0;
    @include flex-center;
    background: rgba(0, 0, 0, 0.05);
    backdrop-filter: blur(4px);

    .error-content {
      @include flex-center;
      flex-direction: column;
      gap: $spacing-sm;
      color: $text-tertiary;

      .error-icon {
        width: 32px;
        height: 32px;
        color: $error-color;
      }

      .error-text {
        font-size: $font-sm;
        font-weight: $font-medium;
      }
    }
  }

  // 加载状态
  &.loading {
    .image {
      opacity: 0;
    }
  }

  // 加载完成状态
  &.loaded {
    .skeleton {
      opacity: 0;
      pointer-events: none;
    }
  }

  // 错误状态
  &.error {
    .image {
      opacity: 0.3;
    }
  }
}

@keyframes shimmer {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}
</style>

